// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module espi_platform_csr #(
    parameter TABLE_VERSION = 32'h0000_0000
) (
    input logic         clk,
    input logic         reset_n,
    input logic         espi_reset_n,
    // espi IO
    input logic         io_reset,
    input logic  [15:0] io_address,
    input logic         io_write,
    input logic  [7:0]  io_writedata,
    input logic         io_read,
    output logic [7:0]  io_readdata,
    output logic        io_waitrequest,
    // Programmed direction
    output logic [7:0] plt_csr0,
    output logic [7:0] plt_csr1,
    output logic [7:0] plt_csr2,
    output logic [7:0] plt_csr3,
    output logic [7:0] plt_csr4,
    output logic [7:0] plt_csr5,
    output logic [7:0] plt_csr6,
    output logic [7:0] plt_csr7,
    output logic [7:0] plt_csr8,
    output logic [7:0] plt_csr9,
    output logic [7:0] plt_csra,
    output logic [7:0] plt_csrb,
    output logic [7:0] plt_csrc,
    output logic [7:0] plt_csrd,
    output logic [7:0] plt_csre,
    output logic [7:0] plt_csrf
);
localparam PLATFORM_OFFSET = 8'h08;
localparam OFFSET_0        = 8'h00;
localparam OFFSET_1        = 8'h01;
localparam OFFSET_2        = 8'h02;
localparam OFFSET_3        = 8'h03;
localparam OFFSET_4        = 8'h04;
localparam OFFSET_5        = 8'h05;
localparam OFFSET_6        = 8'h06;
localparam OFFSET_7        = 8'h07;
localparam OFFSET_8        = 8'h08;
localparam OFFSET_9        = 8'h09;
localparam OFFSET_A        = 8'h0A;
localparam OFFSET_B        = 8'h0B;
localparam OFFSET_C        = 8'h0C;
localparam OFFSET_D        = 8'h0D;
localparam OFFSET_E        = 8'h0E;
localparam OFFSET_F        = 8'h0F;

logic wr_req_plt4;
logic wr_req_plt5;
logic wr_req_plt6;
logic wr_req_plt7;
logic wr_req_plt8;
logic wr_req_plt9;
logic wr_req_plta;
logic wr_req_pltb;
logic wr_req_pltc;
logic wr_req_pltd;
logic wr_req_plte;
logic wr_req_pltf;

logic rd_req_plt0;
logic rd_req_plt1;
logic rd_req_plt2;
logic rd_req_plt3;
logic rd_req_plt4;
logic rd_req_plt5;
logic rd_req_plt6;
logic rd_req_plt7;
logic rd_req_plt8;
logic rd_req_plt9;
logic rd_req_plta;
logic rd_req_pltb;
logic rd_req_pltc;
logic rd_req_pltd;
logic rd_req_plte;
logic rd_req_pltf;

logic platform_csr_dec;

assign wr_req_plt4 = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_4);
assign wr_req_plt5 = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_5);
assign wr_req_plt6 = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_6);
assign wr_req_plt7 = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_7);
assign wr_req_plt8 = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_8);
assign wr_req_plt9 = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_9);
assign wr_req_plta = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_A);
assign wr_req_pltb = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_B);
assign wr_req_pltc = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_C);
assign wr_req_pltd = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_D);
assign wr_req_plte = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_E);
assign wr_req_pltf = io_write & platform_csr_dec & (io_address[7:0]  == OFFSET_F);

assign rd_req_plt0 = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_0);
assign rd_req_plt1 = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_1);
assign rd_req_plt2 = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_2);
assign rd_req_plt3 = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_3);
assign rd_req_plt4 = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_4);
assign rd_req_plt5 = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_5);
assign rd_req_plt6 = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_6);
assign rd_req_plt7 = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_7);
assign rd_req_plt8 = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_8);
assign rd_req_plt9 = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_9);
assign rd_req_plta = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_A);
assign rd_req_pltb = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_B);
assign rd_req_pltc = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_C);
assign rd_req_pltd = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_D);
assign rd_req_plte = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_E);
assign rd_req_pltf = io_read & platform_csr_dec & (io_address[7:0]  == OFFSET_F);

assign platform_csr_dec = (io_address[15:8] == PLATFORM_OFFSET);
assign io_waitrequest   = 1'b0;

// Readback mux
always @(*)
begin
   if ( rd_req_plt0 )
       io_readdata <= plt_csr0;
   else if ( rd_req_plt1 )
       io_readdata <= plt_csr1;
   else if ( rd_req_plt2 )
       io_readdata <= plt_csr2;
   else if ( rd_req_plt3 )
       io_readdata <= plt_csr3;
   else if ( rd_req_plt4 )
       io_readdata <= plt_csr4;
   else if ( rd_req_plt5 )
       io_readdata <= plt_csr5;
   else if ( rd_req_plt6 )
       io_readdata <= plt_csr6;
   else if ( rd_req_plt7 )
       io_readdata <= plt_csr7;
   else if ( rd_req_plt8 )
       io_readdata <= plt_csr8;
   else if ( rd_req_plt9 )
       io_readdata <= plt_csr9;
   else if ( rd_req_plta )
       io_readdata <= plt_csra;
   else if ( rd_req_pltb )
       io_readdata <= plt_csrb;
   else if ( rd_req_pltc )
       io_readdata <= plt_csrc;
   else if ( rd_req_pltd )
       io_readdata <= plt_csrd;
   else if ( rd_req_plte )
       io_readdata <= plt_csre;
   else if ( rd_req_pltf )
       io_readdata <= plt_csrf;
   else
       io_readdata <= 8'd0;
end

// Read only register
always @(posedge clk)
    begin
        plt_csr0 <= TABLE_VERSION[07:00];
        plt_csr1 <= TABLE_VERSION[15:08];
        plt_csr2 <= TABLE_VERSION[23:16];
        plt_csr3 <= TABLE_VERSION[31:24];
    end

// Write decode
always @(posedge clk or posedge io_reset)
begin
    if ( io_reset )
    begin
        plt_csr4 <= 8'd0;
        plt_csr5 <= 8'd0;
        plt_csr6 <= 8'd0;
        plt_csr7 <= 8'd0;
        plt_csr8 <= 8'd0;
        plt_csr9 <= 8'd0;
        plt_csra <= 8'd0;
        plt_csrb <= 8'd0;
        plt_csrc <= 8'd0;
        plt_csrd <= 8'd0;
        plt_csre <= 8'd0;
        plt_csrf <= 8'd0;
    end
    else if ( wr_req_plt4 )
        plt_csr4 <= io_writedata;
    else if ( wr_req_plt5 )
        plt_csr5 <= io_writedata;
    else if ( wr_req_plt6 )
        plt_csr6 <= io_writedata;
    else if ( wr_req_plt7 )
        plt_csr7 <= io_writedata;
    else if ( wr_req_plt8 )
        plt_csr8 <= io_writedata;
    else if ( wr_req_plt9 )
        plt_csr9 <= io_writedata;
    else if ( wr_req_plta )
        plt_csra <= io_writedata;
    else if ( wr_req_pltb )
        plt_csrb <= io_writedata;
    else if ( wr_req_pltc )
        plt_csrc <= io_writedata;
    else if ( wr_req_pltd )
        plt_csrd <= io_writedata;
    else if ( wr_req_plte )
        plt_csre <= io_writedata;
    else if ( wr_req_pltf )
        plt_csrf <= io_writedata;
end

endmodule
